﻿using RM.BasicLibrary.Attributes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace RM.BasicLibrary.Models
{
    public interface ISqlBuilder
    {
        string Insert<T>(T t, string tableName) where T : class;
        string Inserts<T>(List<T> objs, string tableName) where T : class;
        string Update<T>(List<T> objs, string tableName) where T : class;
        string Updates<T>(T entity, string tableName, string whereName = null) where T : class;

    }
    /// <summary>
    /// 对象拼接sql语句
    /// </summary>
    public class SqlBuilder : ISqlBuilder
    {
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public string Insert<T>(T t, string tableName) where T : class
        {
            t.NotNull();
            tableName.NotNull(nameof(tableName));
            string columns = GetColmons(t);
            if (string.IsNullOrEmpty(columns)) return string.Empty;
            string values = GetValues(t);
            if (string.IsNullOrEmpty(values)) return string.Empty;
            StringBuilder sql = new StringBuilder();
            sql.Append("Insert into " + tableName);
            sql.Append("(" + columns + ")");
            sql.Append(" values(" + values + ")");
            return sql.ToString();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="objs"></param>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public string Inserts<T>(List<T> objs, string tableName) where T : class
        {
            objs.NotNull(nameof(objs));
            tableName.NotNull(nameof(tableName));
            string columns = GetColmons(objs[0]);
            if (string.IsNullOrEmpty(columns)) return string.Empty;
            string values = string.Join(",", objs.Select(p => string.Format("({0})", GetValues(p))).ToArray());
            StringBuilder sql = new StringBuilder();
            sql.Append("Insert into " + tableName);
            sql.Append("(" + columns + ")");
            sql.Append(" values " + values + "");
            return sql.ToString();
        }
        /// <summary>
        /// 获得类型的列名
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        private static string GetColmons<T>(T obj)
        {
            if (obj == null) return string.Empty;
            return string.Join(",", obj.GetType().GetProperties().Where(x => Attribute.GetCustomAttribute(x, typeof(PrimaryKeyAttribute)) == null).Select(p => p.Name).ToList());
        }

        /// <summary>
        /// 获得值
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        private static string GetValues<T>(T obj)
        {
            if (obj == null) return string.Empty;
            return string.Join(",", obj.GetType().GetProperties().Where(x => Attribute.GetCustomAttribute(x, typeof(PrimaryKeyAttribute)) == null).Select(p => string.Format("'{0}'", p.GetValue(obj, null))).ToArray());
        }

        /// <summary>
        /// 获得主键名称
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        private static string GetPK<T>(T obj) where T : class
        {
            var objPro = obj.GetType().GetProperties().FirstOrDefault(x => Attribute.GetCustomAttribute(x, typeof(PrimaryKeyAttribute)) != null);
            objPro.NotNull(nameof(objPro));
            return objPro.Name;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="objs"></param>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public string Update<T>(List<T> objs, string tableName) where T : class
        {
            objs.NotNull(nameof(objs));
            tableName.NotNull(nameof(tableName));
            string sql = string.Empty;
            objs.ForEach(x => sql += Updates(x, tableName));
            return sql;
        }
        /// <summary>
        /// sql修改语句
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public string Updates<T>(T entity, string tableName, string whereName = null) where T : class
        {
            if (entity == null || string.IsNullOrEmpty(tableName)) return string.Empty;
            whereName = whereName ?? GetPK<T>(entity);
            whereName.NotNull(nameof(whereName));
            object pkValue = null;
            StringBuilder sb = new StringBuilder();
            sb.Append("update ");
            sb.Append(tableName);
            sb.Append(" set ");
            Type type = entity.GetType();
            PropertyInfo[] props = type.GetProperties();
            List<string> paraList = new List<string>();
            foreach (var prop in props)
                if (prop.Name == whereName) pkValue = prop.GetValue(entity, null);
                else paraList.Add(GetUpdatePara(prop, entity));
            if (paraList.Count == 0) return string.Empty;
            sb.Append(string.Join(",", paraList));
            pkValue.NotNull(nameof(pkValue));
            sb.Append(" where ");
            sb.Append(whereName);
            sb.Append(" = ");
            sb.AppendFormat("'{0}'", pkValue);
            return sb.ToString();
        }

        /// <summary>
        /// 获得修改参数
        /// </summary>
        /// <param name="property"></param>
        /// <returns></returns>
        private static string GetUpdatePara<T>(PropertyInfo property, T entity)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat(" {0}='{1}' ", property.Name, property.GetValue(entity, null));
            return sb.ToString();
        }
    }
}
